<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title></title>
		<script src="../33同步模块模式/module.js"></script>
	</head>

	<body>
		对功能分割成一个个组件,作为一个模块样,分解视图开发。 <br>
		如果这样,我们就要对视图进行分割,将功能融合形成一套完整的组件,来解决视图开发中的耦合问题. <br>
		Widget模式开发中一个组件就要对应一个文件,而不是某个功能或者某个视图, 因此在这个组件文件中需要做两件事,第一创建视图,第二添加相应的功能。 <br>
		接下来先介绍分解和创建视图<br>

		<!--
		模板: 
		<a href="#" class="data-lang {% if(is_selected) { %}selected {% } %}" value="{%=value%}">{%=text%}</a>
		数据: {is_selected:true,value:'zh',text:'zh-text'}
		=>输出结果:<a href="#" class="data-lang selected" value="zh"> zh-text</a>
		-->
		
	</body>
	<script>
		//模板引擎模块
		F.module('lib/template', function() {
			//模板引擎处理数据与编译模板入口
			var _TplEngine = function() {},
				//获取模板
				_getTpl = function() {},
				//处理模板
				_dealTpl = function() {},
				//编译执行
				_compileTpl = function() {};
			return _TplEngine;
		});

		/***
		 *模板引擎 处理数据与编译模板入口
		 *@param str模板容器id或者模板字符串
		 *@param data 渲染数据
		 **/
		_TplEngine = function(str, data) {
			//如果数据是数组
			if(data instanceof Array) {
				//缓存渲染模板结果
				var html = '',
					//数据索引
					i = 0,
					//数据长度
					len = data.length;
				//遍历数据
				for(; i < len; i++) {
					//缓存模板渲染结果, 也可写成html += arguments.callee(str,data[j); 
					html += _getTpl(str)(data[i]);
				}
				//返回模板渲染最终结果
				return html;
			} else {
				//返回模板渲染结果
				return _getTpl(str)(data);
			}
		}

		/***
		 *获取模板
		 * @param str 模板容器id,或者模板字符串
		 **/
		_getTpl = function(str) {
			//获取元素
			var ele = document.getElementById(str);
			//如果元素存在
			if(ele) {
				//如果是input或者textarea表单元素,则获取该元素的value值,否则获取元素的内容
				var html = /^(textarea|input)$/i.test(ele.nodeName) ? ele.value : ele.innerHTML;
				//编译模板
				return _compileTpl(html);
			} else {
				//编译模板
				return _compileTpl(str);
			}
		}
		/*
		第3步,处理模板方法 _dealTpl 首先要明确哪些内容是要被替换的,
		确定替换内容的左右分隔符。接下来要对模板字符串处理,将模板字符串分割并传入编译环境中的template_array数组中。
		由于处理的流程比较复杂,这里举例说明一下:
		例如:模板: <a> {%=test%}</a>
		处理后的形式为template_array.push('<a>' ,typeof(test)==='undefined'?'':test,'</a>');
		首先显性地将传入的内容转化为字符串,这是容错处理。然后将html常用标签内的'&lt;' 和'&gt;'分别转义成'<'和'>',
		将三类空白符(回车符\r,制表符\t,换行符\n)过滤掉。
		然后将'{%=text%}'转化成"',typeof($1)==='undefined'?":$1,'"形式。最后将'{%'替换成"');",
		将'%}'替换成'template_array.push('"'。
		*/
		_dealTpl = function(str) {
			var _left = '{%', //左分隔符
				_right = '%}'; //右分隔符
			//显式转化为字符串
			return String(str)
				//转义标签内的<如: <div>{%if(a&lt;b)%}</div> -> <div> {%if(a<b)%}</div>
				.replace(/&lt;/g, '<')
				//转义标签内的>
				.replace(/&gt;/g, '>')
				//过滤回车符, 制表符, 回车符
				.replace(/[\r\t\n]/g, '')
				//替换内容
				.replace(new RegExp(_left + '=(.*?)' + _right, 'g'), "',typeof($1)==='undefined'?'': $1, '")
				//替换左分隔符
				.replace(new RegExp(_left, 'g'), "');")
				//替换右分隔符
				.replace(new RegExp(right, 'g'), "template_array.push('");
		}

		/***
		 *编译执行
		 *@param str模板数据
		 **/
		_compileTpl = function(str) {
				//编译函数体
				var fnBody = "var template_array=[];\nvar fn=(function(data){\nvar template_key='';\nfor(key in data){\ntemplate_key+=('var '+key+'=data[\"'+key+'\"];');\n}\neval (template_key);\ntemplate_array.push('" + _dealTpl(str) + "');\ntemplate_key=null;\n})(templateData);\nfn = null;\nreturn template_array.join('');"
				//编译函数
				return new Function("templateData", fnBody);
			},

			"//声明template_array模板容器组
			var template_array = [];\n
			//闭包,模板容器组添加成员\n
			var fn = (function(data) {\n
			//渲染数据变量的执行函数体
			var template_key = '';\n
			//遍历渲染数据
			for(key in data) {\n
				//为渲染数据变量的执行函数体添加赋值语句
				template_key += ('var ' + key + '=data[\"' + key + '\"];');\n
				}\n
				//执行渲染数据变量函数
				eval(template_ key);\n
				//为模板容器组添加成员(注意,此时渲染数据将替换容器中的变量)
				template_array.push('"+_dealTpl(str)+"');\n
			//释放渲染数据变量函数
			template_key = null;\n
			//为闭包传入数据
		})(templateData);\n
		//释放闭包
		fn = null;\n
		//返回渲染后的模板容器组,并拼接成字符串
		return template array.join('');"
	</script>

</html>